home *** CD-ROM | disk | FTP | other *** search
/ PC World Interactive 4 / PC World Interactive 4.iso / online / appbar.EXE / csrc / util.cpp < prev   
C/C++ Source or Header  |  1996-09-23  |  28KB  |  1,044 lines

  1. // *********************************************************
  2. // AppBar -- Advanced Menu bar for Windows 95/NT
  3. // All code Copyright (C) 1995, 1996 by Mike Perham
  4. // mperham@cs.cornell.edu
  5. // 
  6. // This code MAY NOT be used for any other program without
  7. // my permission and is forbidden in any shareware/commercial
  8. // program.  This code is provided for educational use only
  9. // and there are no guarantees or promises implied.  Blah blah
  10. // *********************************************************
  11.  
  12. #include "appbar.h"
  13. #include "globals.h"
  14.  
  15.     // Syncs AppBar's timer with the system time
  16. void SyncTime(void)
  17. {
  18.     SYSTEMTIME st;
  19.     GetSystemTime(&st);
  20.     // install timer that goes off at next 10 sec interval (10, 20, 30, etc.)
  21.     SetTimer(ab_hwnd, SYNC_TIMER, ((9-(st.wSecond%10))*1000)+(1000-st.wMilliseconds), NULL);
  22. }
  23.  
  24. // Based on function in MSJ Mar 1996 by Jeffrey Richter.
  25.  
  26. void SlideWindow(int newy)
  27. {
  28.     int y, t_start, t_end, t_curr, hide_time;
  29.     RECT start;
  30.  
  31.     hide_time = (IsShown ? 300 : 200);
  32.     GetWindowRect(ab_hwnd, &start);
  33.     t_start = GetTickCount();
  34.     t_end = t_start + hide_time;
  35. //  This will be smoother if we bump up the priority, but it's not polite
  36. //  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
  37.     while ((t_curr = GetTickCount()) < t_end) {
  38.         y = start.top - (start.top - newy) * (int) (t_curr - t_start) / hide_time;
  39.         SetWindowPos(ab_hwnd, NULL, 0, y, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
  40.         UpdateWindow(ab_hwnd);
  41.     }
  42.     SetWindowPos(ab_hwnd, NULL, 0, newy, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
  43.     UpdateWindow(ab_hwnd);
  44. //  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  45. }
  46.  
  47. // it's hideous, but it does the job...
  48.  
  49. void parse_cmd_args(void)
  50. {
  51.     char msg[80];
  52.     int j;
  53.     user_options args;
  54.     BOOL done = FALSE;
  55.     char filename[MAX_PATH];
  56.  
  57.     strcpy(sys_vars.user, "");
  58.     strcpy(sys_vars.appfile, "");
  59.     memset((void*)&args, 0, sizeof(user_vars));
  60.     // now process the array of parameters
  61.     for (j=1;j<__argc;j++) {
  62.         if (!strncmp(__argv[j], "-", 1)) {
  63.             if (!strncmp((char*)__argv[j]+1, "s", 1))
  64.                 args.stayontop = -1;
  65.               else if (!strncmp((char*)__argv[j]+1, "c", 1))
  66.                 args.chime = -1;
  67.               else if (!strncmp((char*)__argv[j]+1, "b", 1))
  68.                 args.bottom = -1;
  69.               else if (!strncmp((char*)__argv[j]+1, "a", 1))
  70.                 args.autohide = -1;
  71.               else if (!strncmp((char*)__argv[j]+1, "d", 1))
  72.                 args.date = -1;
  73.               else if (!strncmp((char*)__argv[j]+1, "m", 1))
  74.                 args.memory = -1;
  75.               else if (!strncmp((char*)__argv[j]+1, "t", 1))
  76.                 args.time = -1;
  77.               else if (!strncmp((char*)__argv[j]+1, "u", 1))
  78.                 args.user = -1;
  79.               else if (!strncmp((char*)__argv[j]+1, "f", 1)) {
  80.                 if ((j+1 <= __argc)) {
  81.                     char w = *(__argv[j+1]);
  82.                     // if filename does not start with '-' or '+'
  83.                     // assume it is a valid filename
  84.                     if (!((w == '+') || (w == '-')))
  85.                         strcpy((char *)filename, __argv[++j]);
  86.                       else {
  87.                         j++;
  88.                         ab_message(INVALID_FILENAME);
  89.                     }
  90.                 } else
  91.                     ab_message(INVALID_FILENAME);
  92.               } else {
  93.                 sprintf(msg, UNKNOWN_OPTION, __argv[j]);
  94.                 ab_message(msg);
  95.             }
  96.         } else if (!strncmp(__argv[j], "+", 1)) {
  97.             if (!strncmp((char*)__argv[j]+1, "s", 1))
  98.                 args.stayontop = 1;
  99.               else if (!strncmp((char*)__argv[j]+1, "c", 1))
  100.                 args.chime = 1;
  101.               else if (!strncmp((char*)__argv[j]+1, "a", 1))
  102.                 args.autohide = 1;
  103.               else if (!strncmp((char*)__argv[j]+1, "b", 1))
  104.                 args.bottom = 1;
  105.               else if (!strncmp((char*)__argv[j]+1, "d", 1))
  106.                 args.date = 1;
  107.               else if (!strncmp((char*)__argv[j]+1, "m", 1))
  108.                 args.memory = 1;
  109.               else if (!strncmp((char*)__argv[j]+1, "t", 1))
  110.                 args.time = 1;
  111.               else if (!strncmp((char*)__argv[j]+1, "u", 1))
  112.                 args.user = 1;
  113.               else if (!strncmp((char*)__argv[j]+1, "f", 1)) {
  114.                 if ((j+1 <= __argc)) {
  115.                     char w = *(__argv[j+1]);
  116.                     if (!((w == '+') || (w == '-')))
  117.                         strcpy((char *)filename, __argv[++j]);
  118.                       else {
  119.                         j++;
  120.                         ab_message(INVALID_FILENAME);
  121.                     }
  122.                 } else
  123.                     ab_message(INVALID_FILENAME);
  124.               } else {
  125.                 sprintf(msg, UNKNOWN_OPTION, __argv[j]);
  126.                 ab_message(msg);
  127.             }
  128.         } else      // User gave a user configuration
  129.             strcpy((char*)sys_vars.user, __argv[j]);
  130.     } // end while
  131.  
  132.     if (strcmp((char*)sys_vars.user, ""))
  133.         sprintf(sys_vars.appfile, "appbar.%s", sys_vars.user);
  134.  
  135.     if (strcmp(filename, ""))
  136.         strcpy(sys_vars.appfile, filename);
  137.  
  138.     get_reg_keys(&args);
  139. }
  140.  
  141. // Update time on menubar every minute
  142.  
  143. BOOL modify_time(void)
  144. {
  145.     char string[105] = "";
  146.     char time[20] = "";
  147.     char date[25] = "";
  148.     char mem[10] = "";
  149.     char user[40] = "";
  150.     char batt[20] = "";
  151.     static BOOL played_wav;
  152.     SYSTEM_POWER_STATUS sps;
  153.  
  154.     if (IsShown) {
  155.         if (user_vars.user)
  156.             sprintf(user, "%s  ", sys_vars.user);
  157.         
  158.         if (user_vars.time) {
  159.             GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_NOSECONDS, NULL, 
  160.                         NULL, time, sizeof(time));
  161.             strcat(time, "  ");
  162.         }
  163.  
  164.         if (user_vars.date) {
  165.             GetDateFormat(LOCALE_SYSTEM_DEFAULT, NULL, NULL, NULL, 
  166.                         date, sizeof(date));
  167.             strcat(date, "  ");
  168.         }
  169.         
  170.         if (user_vars.memory) {
  171.             MEMORYSTATUS ms;
  172.             GlobalMemoryStatus(&ms);
  173.             sprintf(mem, "%dk ", (int)ms.dwAvailPhys/1024);
  174.         }
  175.  
  176.         if (sys_vars.power) {
  177.             if (sys_vars.battery) {
  178.                     GetSystemPowerStatus(&sps);
  179.                     sprintf(batt, "%d%%", sps.BatteryLifePercent);
  180.                     if (sps.BatteryLifePercent == 255)              // unknown percentage
  181.                         sprintf(batt, "--%%");
  182.                 }
  183.         }
  184.         // final string to print on AppBar
  185.         sprintf(string, "%s%s%s%s%s", user, time, date, mem, batt);
  186.  
  187.         SIZE s;
  188.         int x,y;
  189.         TEXTMETRIC tm;
  190.         COLORREF c;
  191.         HDC hdc;
  192.         HFONT hOldFont, hfnt;
  193.         NONCLIENTMETRICS ncm;
  194.  
  195.         hdc = GetWindowDC(ab_hwnd);
  196.         if (sys_vars.newshell) {
  197.             ncm.cbSize = sizeof(NONCLIENTMETRICS);
  198.             SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
  199.             hfnt = CreateFontIndirect(&(ncm.lfMenuFont));
  200.             hOldFont = (HFONT) SelectObject(hdc, hfnt);
  201.         }
  202.         c = SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
  203.         SetBkMode(hdc, TRANSPARENT);
  204.         GetTextExtentPoint32(hdc, string, strlen(string), &s);
  205.         x = AB_WIDTH - s.cx - 7;
  206.         GetTextMetrics(hdc, &tm);
  207.         y = (int) ((AB_HEIGHT - tm.tmHeight) / 2);
  208.             // Clear menubar and then draw time in menu corner
  209.         DrawMenuBar(ab_hwnd);
  210.         TextOut(hdc, x, y, string, strlen(string));
  211.         if (sys_vars.power) {
  212.             if (sys_vars.battery) {
  213.                 if (sps.BatteryLifePercent > 25)
  214.                     SetTextColor(hdc, GREEN);
  215.                   else if (sps.BatteryLifePercent > 10)
  216.                       SetTextColor(hdc, YELLOW);
  217.                   else
  218.                       SetTextColor(hdc, RED);
  219.                 GetTextExtentPoint32(hdc, batt, strlen(batt), &s);
  220.                 x = AB_WIDTH - s.cx - 7;
  221.                 TextOut(hdc, x, y, batt, strlen(batt));
  222.             }
  223.         }
  224.         if (sys_vars.newshell) {
  225.             SelectObject(hdc, hOldFont); 
  226.             DeleteObject(hfnt);
  227.         }
  228.         SetTextColor(hdc, c);
  229.         ReleaseDC(ab_hwnd, hdc);
  230.     }   // end if (IsShown)
  231.  
  232.     if (user_vars.chime) {
  233.         SYSTEMTIME st;
  234.         GetSystemTime(&st);
  235.  
  236.         // if it's the top of the hour and we haven't already played this minute...
  237.         if ((st.wMinute == 0) && (!played_wav)) {
  238.             played_wav = TRUE;
  239.             if (!PlaySound(user_vars.wavfile, NULL, SND_ASYNC | SND_FILENAME))
  240.                 ab_message(ERROR_PLAYING_WAV);
  241.           } else if (st.wMinute == 1)
  242.             played_wav = FALSE;
  243.     }
  244.     return TRUE;
  245. }
  246.  
  247. ///////// Registry interface /////////////
  248.  
  249. #define SET(a); if (args->a == 1) \
  250.                     user_vars.a = TRUE; \
  251.                  else if (args->a == -1) \
  252.                     user_vars.a = FALSE;
  253.  
  254. void get_reg_keys(user_options *args)
  255. {
  256.     HKEY root;
  257.     DWORD isnew, type, size = sizeof(user_options);
  258.     LONG rc;
  259.     char *p, keyname[80], mike[80];
  260.  
  261.     strcpy(keyname, "Software\\AppBar\\Default");
  262.     // each user gets his own key in the registry
  263.     if (strlen(sys_vars.user)) {
  264.         strcpy(mike, sys_vars.user);
  265.         // this loop will not work with Unicode
  266.         for (p=mike; p<mike+strlen(mike); p++)
  267.             _tolower(*p);
  268.         sprintf(keyname, "Software\\AppBar\\%s", mike);
  269.     }
  270.  
  271.     if (!strcmp(sys_vars.appfile, ""))
  272.         strcpy(sys_vars.appfile, "appbar.default");
  273.     // create or open key
  274.     rc = RegCreateKeyEx(HKEY_CURRENT_USER, keyname, 0, NULL,
  275.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  276.                     NULL, &root, &isnew);
  277.     
  278.     if (rc != ERROR_SUCCESS) {
  279.         ab_message(ERROR_OPENING_REG);
  280.         user_vars.stayontop = TRUE;
  281.         user_vars.chime = FALSE;
  282.         user_vars.date = FALSE;
  283.         user_vars.bottom = FALSE;
  284.         user_vars.memory = TRUE;
  285.         user_vars.autohide = TRUE;
  286.         user_vars.time = TRUE;
  287.         user_vars.user = FALSE;
  288.         strcpy(user_vars.wavfile, "");
  289.         if (strlen(sys_vars.user)) {
  290.             sprintf(keyname, "appbar.%s", sys_vars.user);
  291.             strcpy(sys_vars.appfile, keyname);
  292.         } else
  293.             strcpy(sys_vars.appfile, "appbar.default");
  294.         return;
  295.     }
  296.     
  297.     if (isnew != REG_OPENED_EXISTING_KEY)
  298.         make_new_reg_key(root);
  299.       else {
  300.         rc = RegQueryValueEx(root, "User_Variables", NULL, &type, (PBYTE)&user_vars, &size);
  301.         if (size != sizeof(user_options)) {
  302.             ab_message(OBSOLETE_REG_DATA);
  303.             RegDeleteKey(root, "User_Variables");
  304.             make_new_reg_key(root);
  305.         }
  306.     }
  307.     RegCloseKey(root);
  308.  
  309.         // modify user vars according to cmd args
  310.     SET(date);
  311.     SET(memory);
  312.     SET(stayontop);
  313.     SET(bottom);
  314.     SET(autohide);
  315.     SET(chime);
  316.     SET(time);
  317.     SET(user);
  318.  
  319.     if (!sys_vars.newshell)
  320.         user_vars.autohide = TRUE;
  321. }
  322.  
  323. void make_new_reg_key(HKEY root)
  324. {
  325.     char msg[100];
  326.     char comma[3] = "";
  327.     LONG rc;
  328.  
  329.     if (strcmp(sys_vars.user, ""))
  330.         strcpy(comma, ", ");
  331.     sprintf(msg, WELCOME_MSG, comma, sys_vars.user);
  332.     ab_message(msg);
  333.     user_vars.stayontop = TRUE;
  334.     user_vars.chime = FALSE;
  335.     user_vars.date = FALSE;
  336.     user_vars.bottom = FALSE;
  337.     user_vars.time = TRUE;
  338.     user_vars.user = FALSE;
  339.     user_vars.memory = TRUE;
  340.     user_vars.autohide = TRUE;
  341.     strcpy(user_vars.wavfile, "");
  342.     rc = RegSetValueEx(root, "User_Variables", NULL, REG_BINARY, 
  343.                 (PBYTE) &user_vars, sizeof(user_options));
  344.     if (rc != ERROR_SUCCESS)
  345.         ab_message(ERROR_SAVING_REG);
  346. }
  347.  
  348. void save_reg_keys(void)
  349. {
  350.     HKEY root;
  351.     char keyname[80];
  352.     DWORD isnew;
  353.     LONG rc;
  354.  
  355.     if (strcmp((char*)sys_vars.user, ""))
  356.         sprintf(keyname, "Software\\AppBar\\%s",sys_vars.user);
  357.       else
  358.         strcpy((char*)keyname, "Software\\AppBar\\Default");
  359.  
  360.     rc = RegCreateKeyEx(HKEY_CURRENT_USER, keyname, 0, NULL,
  361.                 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &root, &isnew);
  362.     rc = RegSetValueEx(root, "User_Variables", NULL, REG_BINARY, 
  363.                 (PBYTE)&user_vars, sizeof(user_options));
  364.     if (rc != ERROR_SUCCESS)
  365.         ab_message(ERROR_SAVING_REG);
  366.     RegCloseKey(root);
  367. }
  368.  
  369. // Initialize system-dependent variables
  370.  
  371. BOOL init_app(void)
  372. {
  373.     HWND hOldWnd = FindWindow("ABClass", "AppBar");
  374.     if (hOldWnd) {
  375.         BringWindowToTop(hOldWnd);
  376.         return FALSE;
  377.     }
  378.  
  379.     DWORD dwVersion = GetVersion();
  380.     DWORD dwMajor =  (DWORD)(LOBYTE(LOWORD(dwVersion)));
  381.     DWORD dwMinor =  (DWORD)(HIBYTE(LOWORD(dwVersion)));
  382.  
  383.     if (dwVersion < 0x80000000) {               // Windows NT
  384.         if (dwMajor == 3) {
  385.             sys_vars.newshell = FALSE;
  386.             sys_vars.power = FALSE;
  387.           } else if (dwMajor == 4) {
  388.             sys_vars.newshell = TRUE;
  389.             sys_vars.power = FALSE;
  390.           } else {  // NT5!
  391.             sys_vars.newshell = TRUE;
  392.             sys_vars.power = TRUE;
  393.         }
  394.     } else if (dwMajor < 4)        // Win32s - this should never happen
  395.         return FALSE;
  396.       else {        // Windows 95 -- No build numbers provided
  397.         sys_vars.newshell = TRUE;
  398.         sys_vars.power = TRUE;
  399.     }
  400.  
  401.     if (sys_vars.power) {
  402.         SYSTEM_POWER_STATUS sps;
  403.         GetSystemPowerStatus(&sps);
  404.         if (sps.ACLineStatus)
  405.             sys_vars.battery = FALSE;
  406.           else
  407.             sys_vars.battery = TRUE;
  408.     }
  409.  
  410.     sys_vars.width = GetSystemMetrics(SM_CXSCREEN);
  411.     sys_vars.height = GetSystemMetrics(SM_CYSCREEN);
  412.  
  413.     // copy AppBar's directory to origdir
  414.     
  415.     GetModuleFileName(GetModuleHandle(NULL), origdir, PATH_SIZE);
  416.     char *end = strrchr(origdir, '\\');
  417.     char *front = (char *) origdir;
  418.  
  419.     while (front != end)
  420.         front++;
  421.     *front = '\0';
  422.  
  423.     parse_cmd_args();
  424.     popup = GetSubMenu(LoadMenu(ab_inst, MAKEINTRESOURCE(IDR_MENU)),0);
  425.     return TRUE;
  426. }   
  427.     
  428. // Creates and displays window based on user options    
  429.     
  430. BOOL setup_win(void)
  431. {
  432.     if (!create_appbar())
  433.         return FALSE;
  434.     if (!read_in_apps())
  435.         return FALSE;
  436.     if (!show_appbar())
  437.         return FALSE;                              
  438.     return TRUE;
  439. }
  440.  
  441. // Print error message and exit program
  442.  
  443. void error(char *err_msg)
  444. {
  445.     MessageBox(NULL, err_msg, FATAL_ERROR, MB_OK | MB_ICONSTOP);
  446.     _fcloseall();
  447.     exit_appbar(TRUE);
  448.     PostQuitMessage(-1);
  449. }                            
  450.                          
  451. // Initialize and register window class
  452.  
  453. BOOL create_appbar(void)
  454. {
  455.     ab_wc.style = NULL;                   
  456.     ab_wc.lpfnWndProc = AppBarWinProc;  
  457.                                         
  458.     ab_wc.cbClsExtra = 0;                 
  459.     ab_wc.cbWndExtra = 0;                
  460.     ab_wc.hInstance = ab_inst;           
  461.     ab_wc.hIcon = LoadIcon(ab_inst, MAKEINTRESOURCE(IDI_APPBAR));
  462.     ab_wc.hCursor = NULL;
  463.     if (!sys_vars.newshell)
  464.         ab_wc.hbrBackground = NULL;
  465.       else
  466.         ab_wc.hbrBackground = (HBRUSH) ((DWORD) COLOR_MENU + 1);
  467.     ab_wc.lpszMenuName =  (char *)IDR_MENU;
  468.     ab_wc.lpszClassName = "ABClass"; 
  469.  
  470.     return (RegisterClass(&ab_wc));
  471. }           
  472.  
  473. // Reads in the user spec'd applications
  474.  
  475. BOOL read_in_apps(void)
  476. {               
  477.     FILE *appfile;
  478.     int i, j=0, ver;
  479.     BOOL exist = TRUE;
  480.     char msg[80];
  481.     menu_struct *cur_menu, *nextmenu, *prevmenu;
  482.     app_struct *cur_app, *nextapp, *prevapp;
  483.  
  484.     // Create binary data file if none exists                            
  485.     
  486.     _chdir(origdir);
  487.     if ((appfile = fopen(sys_vars.appfile, "r")) == NULL)
  488.         exist = FALSE;
  489.                                              
  490.     // Read application data until the end of the file
  491.     // this tests for zero-length data files (exist, but are empty)
  492.     if (exist)
  493.         if (_filelength(_fileno(appfile)) == 0)
  494.             exist = FALSE;
  495.  
  496.     if (exist) {
  497.         fread(&ver, sizeof(int), 1, appfile);
  498.         if (ver != APPBAR_FILE_VERSION)
  499.             error(OLD_DATAFILE_FORMAT);
  500.         cur_menu = new menu_struct;
  501.         glob_menu = cur_menu;
  502.         nextmenu = cur_menu;
  503.         prevmenu = NULL;
  504.         while (fread(nextmenu, sizeof(menu_struct), 1, appfile)) {
  505.             j++;
  506.             cur_menu = nextmenu;
  507.             cur_menu->nextapp = NULL;
  508.             prevapp = NULL;
  509.             cur_menu->prevmenu = prevmenu;
  510.             if (nextmenu->numapps) {
  511.                 cur_app = new app_struct;
  512.                 cur_menu->nextapp = cur_app;
  513.                 for (i=cur_menu->numapps;i>0; i--) {
  514.                     if (!fread(cur_app, sizeof(app_struct), 1, appfile)) {
  515.                         sprintf(msg, ERROR_READING_MENUS, j,
  516.                                         cur_menu->numapps - i + 1, sys_vars.appfile);
  517.                         error(msg);
  518.                     }
  519.                     cur_app->prevapp = prevapp;
  520.                     prevapp = cur_app;
  521.                     if (i-1) {
  522.                         cur_app->nextapp = new app_struct;
  523.                         cur_app = cur_app->nextapp;
  524.                       } else cur_app->nextapp = NULL;
  525.                 }
  526.             }
  527.             prevmenu = cur_menu;
  528.             nextmenu = new menu_struct;
  529.             nextmenu->prevmenu = cur_menu;
  530.             cur_menu->nextmenu = nextmenu;
  531.         }
  532.         // Reached EOF.  Now we need to delete that last menu, since it was
  533.         // created before we knew it was EOF.
  534.         delete nextmenu;
  535.         cur_menu->nextmenu = NULL;
  536.         fclose(appfile);
  537.     } else {
  538.         // Create default menu structure 
  539.         char path[80];
  540.         menu_struct *tempmenu;
  541.  
  542.         tempmenu = new menu_struct;
  543.         strcpy(tempmenu->menuname,"&Apps");
  544.         tempmenu->numapps = 2;
  545.  
  546.         tempmenu->nextapp = new app_struct;
  547.         strcpy(tempmenu->nextapp->appexe, "c:\\vc40\\bin\\msdev.exe");
  548.         strcpy(tempmenu->nextapp->appname, "Visual &C++ v4.0");
  549.         cur_app = tempmenu->nextapp;
  550.  
  551.         nextapp = new app_struct;
  552.         cur_app->nextapp = nextapp;
  553.         nextapp->prevapp = cur_app;
  554.         strcpy(nextapp->appexe, "c:\\winword\\winword.exe");
  555.         strcpy(nextapp->appname, "&Word v7.0");
  556.         glob_menu = tempmenu;
  557.  
  558.         tempmenu = new menu_struct;
  559.         glob_menu->nextmenu = tempmenu;
  560.         tempmenu->prevmenu = glob_menu;
  561.         strcpy(tempmenu->menuname,"&Games");
  562.         tempmenu->numapps = 2;
  563.         
  564.         tempmenu->nextapp = new app_struct;
  565.         GetWindowsDirectory(path, sizeof(path));
  566.         strcat(path,"\\winmine.exe");
  567.         strcpy(tempmenu->nextapp->appexe, path);
  568.         strcpy(tempmenu->nextapp->appname, "&Minesweeper");
  569.         cur_app = tempmenu->nextapp;
  570.  
  571.         nextapp = new app_struct;
  572.         cur_app->nextapp = nextapp;
  573.         nextapp->prevapp = cur_app;
  574.         GetWindowsDirectory(path, sizeof(path));
  575.         strcat(path,"\\sol.exe");
  576.         strcpy(nextapp->appexe, path);
  577.         strcpy(nextapp->appname, "&Solitaire");
  578.     }
  579.     return TRUE;
  580. }                                 
  581.  
  582. // Exit function for appbar
  583.  
  584. void exit_appbar(BOOL error_exit)
  585. {
  586.     if (!error_exit) {  // if error, just bomb out...
  587.         save_menus();
  588.         save_reg_keys();
  589.         release_app_memory();
  590.     }
  591.     destroy_window();
  592. }   
  593.  
  594. // Release application linked list memory
  595.  
  596. void release_app_memory(void)
  597. {             
  598.     menu_struct *menu, *front;
  599.     
  600.     menu = glob_menu;
  601.     if (!menu)
  602.         return;
  603.     front = menu->nextmenu;
  604.     while (front!=NULL) {            
  605.         killmenu(menu);
  606.         menu = front;
  607.         front = front->nextmenu;
  608.     }
  609.     killmenu(menu);
  610. }
  611.  
  612. // Deletes menu list and frees resources
  613.  
  614. void kill_applist(void)
  615. {
  616.     app_list *curapplist;
  617.  
  618.     if (applist) {                  // Kill off old app list
  619.         curapplist = applist;
  620.         while (curapplist!=NULL) {
  621.             curapplist = applist->next;
  622.             delete applist;
  623.             applist = curapplist;
  624.         }
  625.     }
  626. }
  627.  
  628. void killmenu(menu_struct *menu)
  629. {
  630.     app_struct *app, *front;
  631.  
  632.     if (!menu)                  // Null menu
  633.         return;
  634.     app = menu->nextapp;
  635.     if  (!app) {                // Menu w/o applications (?)
  636.         delete menu;
  637.         return;
  638.     }
  639.     front = app->nextapp;
  640.     while (front!=NULL) {
  641.         delete app;
  642.         app = front;
  643.         front = front->nextapp;
  644.     }
  645.     delete app;
  646.     delete menu;
  647. }
  648.  
  649. // Updates app linked list and deletes app node
  650. // DOES NOT update menu->nextapp (calling code should)
  651.  
  652. void killapp(app_struct * app)
  653. {
  654.     if (!app)
  655.         return;
  656.     delete app;
  657. }
  658.  
  659. // Unregister and destroy window class    
  660.     
  661. void destroy_window(void)
  662. {
  663.     if (sys_vars.newshell) {
  664.         abd.cbSize = sizeof(APPBARDATA);
  665.         abd.hWnd = ab_hwnd;
  666.         abd.uEdge = (user_vars.bottom ? ABE_BOTTOM : ABE_TOP);
  667.         abd.lParam = FALSE;
  668.         SHAppBarMessage(ABM_SETAUTOHIDEBAR, &abd);
  669.         SHAppBarMessage(ABM_REMOVE, &abd);
  670.     }
  671.     DestroyIcon(ab_wc.hIcon);
  672.     DestroyMenu(ab_menu);
  673.     DestroyMenu(popup);
  674.     KillTimer(ab_hwnd, TIME_UPDATE);
  675.     KillTimer(ab_hwnd, HIDE_TIMER);
  676.     KillTimer(ab_hwnd, SYNC_TIMER);
  677.     DestroyWindow(ab_hwnd);
  678.     UnregisterClass("ABClass", ab_inst);
  679. }
  680.  
  681. inline void ab_message(char * msg)
  682. {
  683.     MessageBox(ab_hwnd, msg, "AppBar", MB_OK | MB_ICONEXCLAMATION);
  684. }
  685.  
  686. // Execute application pointed to by app
  687.  
  688. BOOL execute_application(app_struct * app)
  689. {
  690.     char msg[200];
  691.     DWORD error;
  692.  
  693.     if (sys_vars.newshell) {
  694.         char file[80];
  695.         char dir[80];
  696.         char params[80];
  697.         int show;
  698.         SHELLEXECUTEINFO sei;
  699.  
  700.         sei.cbSize = sizeof(SHELLEXECUTEINFO);
  701.         sei.fMask = SEE_MASK_DOENVSUBST | SEE_MASK_NOCLOSEPROCESS;
  702.         sei.hwnd = ab_hwnd;
  703.         sei.lpVerb = "open";
  704.  
  705.         if (IsLink(app->appexe)) {
  706.             if (!SUCCEEDED(GetLinkInfo(ab_hwnd, app->appexe, (LPSTR)file, (LPSTR)dir, (LPSTR)params, &show))) {
  707.                 ab_message(ERROR_LINK);
  708.                 return FALSE;
  709.             }
  710.             sei.lpFile = file;
  711.             sei.lpDirectory = dir;
  712.             sei.lpParameters = params;
  713.             sei.nShow = show;
  714.           } else {
  715.             sei.lpFile = app->appexe;
  716.             sei.lpParameters = app->params;
  717.             sei.lpDirectory = app->workingdir;
  718.             sei.nShow = app->show;
  719.         }
  720.         ShellExecuteEx(&sei);
  721.  
  722.     } else {
  723.         error = (DWORD) ShellExecute(ab_hwnd, "open", app->appexe, app->params, app->workingdir, app->show);
  724.         if (error < 32) {
  725.             switch (error) {
  726.                 case ERROR_FILE_NOT_FOUND:
  727.                     sprintf(msg, FILE_NOT_FOUND, app->appexe);
  728.                     break;
  729.                 case ERROR_PATH_NOT_FOUND:
  730.                     sprintf(msg, PATH_NOT_FOUND, app->appexe);
  731.                     break;
  732.                 default:
  733.                     sprintf(msg, RETURNED_ERROR, error);
  734.                     break;
  735.             }
  736.             ab_message(msg);
  737.             return 0;
  738.         }
  739.     }
  740.     return 1;
  741. }
  742.  
  743. // the file is a link if it ends in ".LNK"
  744.  
  745. BOOL IsLink(char *filename)
  746. {
  747.     int len = strlen(filename);
  748.     char *extension = filename + len - 4;
  749.  
  750.     if (_strnicmp(extension, ".lnk", 4))
  751.         return FALSE;
  752.     return TRUE;
  753. }
  754.  
  755. // This hideous function courtesy of MS's Knowledge Base (search VC4 help for IShellLink)
  756.  
  757. HRESULT GetLinkInfo(HWND hWnd, LPSTR lpszLinkName, LPSTR lpszFile, LPSTR lpszDir, LPSTR lpszArgs, int *show)
  758.     HRESULT hres;
  759.     IShellLink *psl;
  760.     WIN32_FIND_DATA wfd;
  761.  
  762.     CoInitialize(0);
  763.     hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  764.                            IID_IShellLink,(LPVOID *)&psl );
  765.    
  766.     if (SUCCEEDED(hres)) {
  767.         IPersistFile *ppf;
  768.         hres = psl->QueryInterface(IID_IPersistFile,(LPVOID *)&ppf);
  769.         if (SUCCEEDED(hres)) {
  770.             WORD linkName[MAX_PATH];
  771.             MultiByteToWideChar(CP_ACP, 0, lpszLinkName, -1, linkName, MAX_PATH);
  772.             hres = ppf->Load(linkName, STGM_READ);
  773.             if (SUCCEEDED(hres)) {
  774.                 // Resolve the link by calling the Resolve() interface function.
  775.                 hres = psl->Resolve(hWnd, SLR_ANY_MATCH | SLR_NO_UI);
  776.                 if (SUCCEEDED(hres)) {
  777.                     hres = psl->GetPath(lpszFile, MAX_PATH, &wfd, SLGP_SHORTPATH);
  778.                     hres = psl->GetWorkingDirectory(lpszDir, MAX_PATH );
  779.                     hres = psl->GetArguments(lpszArgs, MAX_PATH);
  780.                     hres = psl->GetShowCmd(show);
  781.                     if (!SUCCEEDED(hres))
  782.                         goto cleanup;
  783.                 }
  784.             }
  785.             ppf->Release();
  786.         }
  787.         psl->Release();
  788.     }
  789.     goto cleanup;
  790.  
  791. cleanup:
  792.     CoUninitialize();
  793.     return hres;
  794. }
  795.  
  796.  
  797. LRESULT CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  798. {
  799.     switch (message) {
  800.         case WM_INITDIALOG:
  801.             return TRUE;
  802.         case WM_COMMAND:
  803.             if (LOWORD(wParam) == IDOK) {
  804.                 EndDialog(hDlg, TRUE);
  805.                 return TRUE;
  806.             }
  807.             break;
  808.         default:
  809.             return FALSE;
  810.     }
  811.     return FALSE;
  812. }
  813. /*
  814. LRESULT CALLBACK RunProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  815. {
  816.     switch (message) {
  817.         case WM_INITDIALOG:
  818.             SetFocus(GetDlgItem(hDlg, IDC_RUNTEXT));
  819.             return FALSE;
  820.         case WM_COMMAND:
  821.             if (LOWORD(wParam) == IDOK) {
  822.                 char command[120];
  823.  
  824.                 SHELLEXECUTEINFO sei;
  825.                 SendMessage(GetDlgItem(hDlg, IDC_RUNTEXT), WM_GETTEXT, sizeof(command), (LPARAM)command);
  826.                 if (strcmp(command, "")) {
  827.                     char *token = command;
  828.                     char *exe = command;
  829.                     char params[80];
  830.  
  831.                     // we have to tokenize the command line into EXE and parameters...
  832.                     // POINTER STEW (obfuscated C joke)
  833.                     while (*token != ' ' && *token != NULL) {
  834.                         if (*token == '"') {
  835.                             exe++;
  836.                             while ((*(token+1)) != '"')
  837.                                 token++;
  838.                             token += 2;
  839.                             *(token-1) = '\0';
  840.                             break;
  841.                         } else
  842.                             token++;
  843.                     }
  844.  
  845.                     strcpy(params, "");
  846.                     if (token != NULL)
  847.                         strcpy(params, token+1);
  848.                     *token = '\0';
  849.  
  850.                     sei.fMask = SEE_MASK_DOENVSUBST | SEE_MASK_NOCLOSEPROCESS;
  851.                     sei.cbSize = sizeof(SHELLEXECUTEINFO);
  852.                     sei.hwnd = ab_hwnd;
  853.                     sei.lpVerb = NULL;
  854.                     sei.lpFile = exe;
  855.                     sei.lpParameters = params;
  856.                     sei.lpDirectory = NULL;
  857.                     sei.nShow = SW_NORMAL;
  858.                     ShellExecuteEx(&sei);
  859.                 }
  860.                 EndDialog(hDlg, TRUE);
  861.                 return TRUE;
  862.             } else if (wParam == IDCANCEL) {
  863.                 EndDialog(hDlg, TRUE);
  864.                 return TRUE;
  865.             }               
  866.             break;
  867.         default:
  868.             return FALSE;
  869.     }
  870.     return FALSE;
  871. }
  872. */
  873. // Finds menu by name in list
  874.  
  875. menu_struct * find_menu(char * menu_sel)
  876. {
  877.     menu_struct * menu;
  878.  
  879.     for (menu = glob_menu; menu != NULL; menu = menu->nextmenu)
  880.         if (!strcmp(menu->menuname,menu_sel))
  881.             return menu;
  882.     ab_message(ERROR_FINDING_MENU);   
  883.     return NULL;
  884. }
  885.  
  886. app_struct * find_app(app_struct * apps, char * app_sel)
  887. {
  888.     app_struct * app;
  889.  
  890.     if (!strcmp(app_sel, SEPARATOR_STRING))
  891.         return NULL;
  892.     for (app = apps; app != NULL; app = app->nextapp)
  893.         if (!strcmp(app_sel,app->appname))
  894.             return app;
  895.     ab_message(ERROR_FINDING_APP);
  896.     return NULL;
  897. }
  898.  
  899. void save_menus(void)
  900. {
  901.     app_struct * pCurApp;
  902.     menu_struct * pCurMenu;
  903.     app_struct *next, *prev, *nexta;
  904.     menu_struct *nextm, *prevm;
  905.     char * datafile, msg[80];
  906.     FILE * pDataFile;
  907.     int i;
  908.     
  909.     _chdir(origdir);
  910.     if (strcmp(sys_vars.appfile, ""))
  911.         datafile = (char *)sys_vars.appfile;
  912.       else
  913.         datafile = "default.ab";
  914.     pDataFile = fopen(datafile, "wb");      // Open for binary write
  915.  
  916.     if (!pDataFile) {
  917.         sprintf(msg, ERROR_OPENING_DATAFILE, datafile);
  918.         ab_message(msg);
  919.         return;
  920.     }
  921.     
  922.     i = APPBAR_FILE_VERSION;
  923.     fwrite(&i, sizeof(int), 1, pDataFile);
  924.     for (pCurMenu = glob_menu; pCurMenu != NULL; pCurMenu = pCurMenu->nextmenu) {
  925.         nextm = pCurMenu->nextmenu;
  926.         prevm = pCurMenu->prevmenu;
  927.         nexta = pCurMenu->nextapp;
  928.         pCurMenu->nextapp = NULL;
  929.         pCurMenu->nextmenu = NULL;
  930.         pCurMenu->prevmenu = NULL;
  931.         fwrite(pCurMenu, sizeof(menu_struct), 1, pDataFile);
  932.         pCurMenu->nextapp = nexta;
  933.         pCurMenu->nextmenu = nextm;
  934.         pCurMenu->prevmenu = prevm;
  935.         for (pCurApp = pCurMenu->nextapp; pCurApp != NULL; pCurApp = pCurApp->nextapp) {
  936.             next = pCurApp->nextapp;
  937.             prev = pCurApp->prevapp;
  938.             pCurApp->nextapp = NULL;
  939.             pCurApp->prevapp = NULL;
  940.             fwrite(pCurApp, sizeof(app_struct), 1, pDataFile);
  941.             pCurApp->nextapp = next;
  942.             pCurApp->prevapp = prev;
  943.         }
  944.     }
  945.     fclose(pDataFile);
  946. }
  947.  
  948. void DoBrowse(int type, HWND parent) 
  949.     OPENFILENAME ofn;
  950.     char szFile[80];
  951.     
  952.     strcpy(szFile,""); 
  953.  
  954.     ofn.lStructSize       = sizeof(OPENFILENAME); 
  955.     ofn.hwndOwner         = parent; 
  956.     ofn.hInstance         = NULL; 
  957.     ofn.lpstrFilter       = (type ? WAV_FILE_TYPES : EXE_FILE_TYPES); 
  958.     ofn.lpstrCustomFilter = NULL; 
  959.     ofn.nMaxCustFilter    = 0L; 
  960.     ofn.nFilterIndex      = 1L; 
  961.     ofn.lpstrFile         = szFile; 
  962.     ofn.nMaxFile          = sizeof(szFile); 
  963.     ofn.lpstrFileTitle    = NULL; 
  964.     ofn.nMaxFileTitle     = 0; 
  965.     ofn.lpstrInitialDir   = "C:\\"; 
  966.     ofn.lpstrTitle        = (type ? FIND_WAV : FIND_EXE); 
  967.     ofn.nFileOffset       = 0; 
  968.     ofn.nFileExtension    = 0; 
  969.     ofn.lpstrDefExt       = NULL; 
  970.     ofn.lCustData         = 0; 
  971.     ofn.Flags             = OFN_SHOWHELP | OFN_PATHMUSTEXIST
  972.                                      | OFN_FILEMUSTEXIST 
  973.                                      | OFN_HIDEREADONLY; 
  974.     if (GetOpenFileName(&ofn))
  975.         if (type) { // Wav file 
  976.             SendMessage(GetDlgItem(parent, IDC_WAVNAME), WM_SETTEXT, 0, (LPARAM)ofn.lpstrFile);
  977.             SetFocus(GetDlgItem(parent, IDOK));
  978.           } else {  // Application executable
  979.             SendMessage(GetDlgItem(parent, IDC_EXENAME), WM_SETTEXT, 0, (LPARAM)ofn.lpstrFile);
  980.             SetFocus(GetDlgItem(parent, IDOK));
  981.         }
  982.  
  983. ///////////////////////////////////////////////////////////////////////////
  984. //  C++ Constructors and Destructors                                     //
  985. ///////////////////////////////////////////////////////////////////////////
  986.  
  987. menu_struct::menu_struct()
  988. {
  989.     memset((void*)menuname, 0, sizeof(menuname));
  990.     numapps = 0;
  991.     nextmenu = NULL;
  992.     prevmenu = NULL;
  993.     nextapp = NULL;
  994. }
  995.  
  996. menu_struct::~menu_struct()
  997. {
  998.     if (nextmenu == NULL) {
  999.         if (prevmenu != NULL)
  1000.             prevmenu->nextmenu = NULL;
  1001.           else
  1002.             glob_menu = NULL;
  1003.       } 
  1004.     else if (prevmenu == NULL) {
  1005.         glob_menu = nextmenu;
  1006.         nextmenu->prevmenu = NULL;
  1007.       } 
  1008.     else {
  1009.         if (prevmenu)
  1010.             prevmenu->nextmenu = nextmenu;
  1011.         if (nextmenu) 
  1012.             nextmenu->prevmenu = prevmenu;
  1013.     }
  1014. }
  1015.  
  1016. app_struct::app_struct()
  1017. {
  1018.     memset((void*)appexe, 0, sizeof(appexe));
  1019.     memset((void*)workingdir, 0, sizeof(workingdir));
  1020.     memset((void*)params, 0, sizeof(params));
  1021.     memset((void*)appname, 0, sizeof(appname));
  1022.     show = SW_SHOW;
  1023.     separator = FALSE;
  1024.     nextapp = NULL;
  1025.     prevapp = NULL;
  1026. }
  1027.  
  1028. app_struct::~app_struct()
  1029. {
  1030.     if (nextapp == NULL) {
  1031.         if (prevapp != NULL)
  1032.             prevapp->nextapp = NULL;
  1033.       } 
  1034.     else if (prevapp == NULL)
  1035.         nextapp->prevapp = NULL;
  1036.     else {
  1037.         prevapp->nextapp = nextapp;
  1038.         nextapp->prevapp = prevapp;
  1039.     }
  1040. }
  1041.